{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torchvision.transforms as transforms\n",
    "import pandas as pd\n",
    "import os\n",
    "from tqdm import tqdm\n",
    "from sklearn.ensemble import RandomForestClassifier\n",
    "from sklearn.metrics import classification_report\n",
    "from itertools import combinations\n",
    "from math import comb\n",
    "\n",
    "# 设置数据集的路径和下载选项\n",
    "Dataset_dir = '../data'\n",
    "Output_dir = './results'\n",
    "\n",
    "train_metrics_dir = os.path.join(Output_dir, 'train_metrics.csv')\n",
    "test_metrics_dir = os.path.join(Output_dir, 'test_metrics.csv')\n",
    "#如果输出目录不存在，则创建\n",
    "if not os.path.exists(Output_dir):\n",
    "    os.makedirs(Output_dir)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [],
   "source": [
    "def add_custom_label(df, label_one_classes, label_zero_classes):\n",
    "    \"\"\"\n",
    "    为DataFrame添加自定义标签列。\n",
    "    \n",
    "    参数:\n",
    "    df (pd.DataFrame): 包含图像标签的DataFrame。\n",
    "    label_one_classes (list): 应该标记为1的类别列表。\n",
    "    label_zero_classes (list): 应该标记为0的类别列表。\n",
    "    \n",
    "    返回:\n",
    "    pd.DataFrame: 添加了自定义标签列并去除了未指定标签行的DataFrame。\n",
    "    \"\"\"\n",
    "    # 使用apply函数为每一行添加自定义标签\n",
    "    df['special_label'] = df['cifar100_label'].apply(lambda x: 1 if x in label_one_classes \n",
    "                                                     else 0 if x in label_zero_classes \n",
    "                                                     else None)\n",
    "    # 去除special_label为None的行\n",
    "    df = df.dropna(subset=['special_label'])\n",
    "    \n",
    "    # 确保idx是第一列\n",
    "    if 'idx' in df.columns:\n",
    "        # 将special_label列插入到idx列后面\n",
    "        df.insert(loc=df.columns.get_loc('idx') + 1, column='special_label', value=df.pop('special_label'))\n",
    "    else:\n",
    "        # 如果没有idx列，将special_label列插入到第一列\n",
    "        df.insert(loc=0, column='special_label', value=df.pop('special_label'))\n",
    "    \n",
    "    return df\n",
    "\n",
    "\n",
    "def train_and_evaluate_combo(train_df, test_df, use_all_features=False, selected_features=None):\n",
    "    if use_all_features:\n",
    "        # 选择除了'special_label'和'idx'列之外的所有列作为特征\n",
    "        X_train = train_df.iloc[:, 2:]\n",
    "        y_train = train_df['special_label']\n",
    "        X_test = test_df.iloc[:, 2:]\n",
    "        y_test = test_df['special_label']\n",
    "    else:\n",
    "        # 使用指定的特征列\n",
    "        X_train = train_df[selected_features]\n",
    "        y_train = train_df['special_label']\n",
    "        X_test = test_df[selected_features]\n",
    "        y_test = test_df['special_label']\n",
    "    \n",
    "    rf = RandomForestClassifier(\n",
    "        n_estimators=300,        # 增加树的数量\n",
    "        max_depth=15,            # 限制树的最大深度\n",
    "        min_samples_split=5,     # 内部节点最小样本数\n",
    "        min_samples_leaf=2,      # 叶子节点最小样本数\n",
    "        max_features='sqrt',     # 使用平方根的特征数\n",
    "        random_state=42\n",
    "    )\n",
    "    rf.fit(X_train, y_train)\n",
    "    \n",
    "    y_pred = rf.predict(X_test)\n",
    "    report = classification_report(y_test, y_pred, output_dict=True)\n",
    "    \n",
    "    # 获取特征重要性\n",
    "    feature_importances = rf.feature_importances_\n",
    "    \n",
    "    # 获取特征列名\n",
    "    features = X_train.columns\n",
    "    \n",
    "    # 对特征重要性进行排序，并获取排序后的列名\n",
    "    sorted_features = features[feature_importances.argsort()][::-1]\n",
    "    \n",
    "    # 返回分类报告、特征重要性和排序后的特征列名\n",
    "    return report, feature_importances, sorted_features\n",
    "\n",
    "def print_classification_report(report, sorted_features, show_avg=False):\n",
    "    print(\"分类报告:\\n\")\n",
    "    \n",
    "    # 首先打印每个类别的性能指标\n",
    "    for class_label, value in report.items():\n",
    "        if isinstance(value, dict) and class_label not in ['macro avg', 'weighted avg']:\n",
    "            print(f\"类别 {class_label}:\")\n",
    "            for metric, val in value.items():\n",
    "                if metric == 'support':\n",
    "                    print(f\"  {metric.replace('_', ' ').title()}: {val}\")\n",
    "                else:\n",
    "                    print(f\"  {metric.replace('_', ' ').title()}: {val:.2%}\")\n",
    "            print()  # 打印一个空行以分隔各个类别\n",
    "\n",
    "    # 如果show_avg为True，打印宏平均和加权平均\n",
    "    if show_avg:\n",
    "        for avg_label, avg_value in report.items():\n",
    "            if avg_label in ['macro avg', 'weighted avg']:\n",
    "                print(f\"类别 {avg_label}:\")\n",
    "                for metric, val in avg_value.items():\n",
    "                    if metric == 'support':\n",
    "                        print(f\"  {metric.replace('_', ' ').title()}: {val}\")\n",
    "                    else:\n",
    "                        print(f\"  {metric.replace('_', ' ').title()}: {val:.2%}\")\n",
    "                print()  # 打印一个空行以分隔各个平均值\n",
    "\n",
    "    # 打印准确率\n",
    "    if 'accuracy' in report:\n",
    "        print(f\"Accuracy: {report['accuracy']:.2%}\")\n",
    "\n",
    "    # 打印排序后的特征列名，并加上序号\n",
    "    print(\"\\n排序后的特征列名:\")\n",
    "    for index, feature in enumerate(sorted_features, start=1):\n",
    "        print(f\"{index}. {feature}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 假设Output_dir已经被定义，并且是包含cifar100_results.csv的目录\n",
    "train_metrics_file = train_metrics_dir\n",
    "test_metrics_file = test_metrics_dir\n",
    "train_df= pd.read_csv(train_metrics_file,index_col='idx')\n",
    "test_df= pd.read_csv(test_metrics_file,index_col='idx')\n",
    "\n",
    "# 定义类别列表\n",
    "label_one_classes = [13, 20, 56, 24, 25, 42, 67, 0, 36, 47]\n",
    "label_zero_classes = [7, 37, 4, 12, 79, 71, 55, 3, 40, 63]\n",
    "\n",
    "train_df= add_custom_label(train_df,label_one_classes,label_zero_classes)\n",
    "test_df= add_custom_label(test_df,label_one_classes,label_zero_classes)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "# 假设report, feature_importances和sorted_features是已经准备好的分类报告字典、特征重要性和排序后的特征列名\n",
    "# 调用函数\n",
    "report, feature_importances, sorted_features = train_and_evaluate_combo(train_df, test_df, use_all_features=True)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "分类报告:\n",
      "\n",
      "类别 0.0:\n",
      "  Precision: 60.86%\n",
      "  Recall: 67.80%\n",
      "  F1-Score: 64.14%\n",
      "  Support: 1000.0\n",
      "\n",
      "类别 1.0:\n",
      "  Precision: 63.66%\n",
      "  Recall: 56.40%\n",
      "  F1-Score: 59.81%\n",
      "  Support: 1000.0\n",
      "\n",
      "Accuracy: 62.10%\n",
      "\n",
      "排序后的特征列名:\n",
      "1. EN\n",
      "2. SF\n",
      "3. SNR\n",
      "4. AG\n",
      "5. SD\n",
      "6. BRISQUE\n"
     ]
    }
   ],
   "source": [
    "print_classification_report(report, sorted_features,show_avg=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'features = [\\'SNR\\', \\'EN\\', \\'SF\\', \\'SD\\', \\'AG\\']\\ndf = {}\\n# y = results[\\'special_label\\']  # 标签向量\\n\\nfor feature in tqdm(features, desc=\"Processing features\"):\\n    accuracy,f1_score = train_and_evaluate(feature,train_df,test_df)\\n    df[feature] = {\\'accuracy\\':accuracy, \\'f1_score\\':f1_score}\\n\\n# 输出结果\\nfor feature, metrics in df.items():\\n    print(f\"Feature: {feature}, Accuracy: {metrics[\\'accuracy\\']:.2f}, F1-score: {metrics[\\'f1_score\\']:.2f}\")'"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "'''features = ['SNR', 'EN', 'SF', 'SD', 'AG']\n",
    "df = {}\n",
    "# y = results['special_label']  # 标签向量\n",
    "\n",
    "for feature in tqdm(features, desc=\"Processing features\"):\n",
    "    accuracy,f1_score = train_and_evaluate(feature,train_df,test_df)\n",
    "    df[feature] = {'accuracy':accuracy, 'f1_score':f1_score}\n",
    "\n",
    "# 输出结果\n",
    "for feature, metrics in df.items():\n",
    "    print(f\"Feature: {feature}, Accuracy: {metrics['accuracy']:.2f}, F1-score: {metrics['f1_score']:.2f}\")'''"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'features = [\\'SNR\\', \\'EN\\', \\'SF\\', \\'SD\\', \\'AG\\']\\ndf = {}\\n\\n# 计算总的组合数量\\ntotal_combinations = sum(comb(len(features), r) for r in range(1, len(features) + 1))\\n\\n# 验证特征组合\\ncombo_progress = tqdm(total=total_combinations)\\nfor r in range(1, len(features) + 1):\\n    for combo in combinations(features, r):\\n        combo_progress.update(1)  # 更新进度条\\n        combo_list = list(combo)\\n        accuracy, f1_score = train_and_evaluate_combo(combo_list, train_df, test_df)\\n        df[combo] = {\\'accuracy\\': accuracy, \\'f1_score\\': f1_score}\\ncombo_progress.close()  # 完成后关闭进度条\\n\\n# 输出结果\\nfor combo, metrics in df.items():\\n    print(f\"Features: {combo}, Accuracy: {metrics[\\'accuracy\\']:.2f}, F1-score: {metrics[\\'f1_score\\']:.2f}\")'"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "'''features = ['SNR', 'EN', 'SF', 'SD', 'AG']\n",
    "df = {}\n",
    "\n",
    "# 计算总的组合数量\n",
    "total_combinations = sum(comb(len(features), r) for r in range(1, len(features) + 1))\n",
    "\n",
    "# 验证特征组合\n",
    "combo_progress = tqdm(total=total_combinations)\n",
    "for r in range(1, len(features) + 1):\n",
    "    for combo in combinations(features, r):\n",
    "        combo_progress.update(1)  # 更新进度条\n",
    "        combo_list = list(combo)\n",
    "        accuracy, f1_score = train_and_evaluate_combo(combo_list, train_df, test_df)\n",
    "        df[combo] = {'accuracy': accuracy, 'f1_score': f1_score}\n",
    "combo_progress.close()  # 完成后关闭进度条\n",
    "\n",
    "# 输出结果\n",
    "for combo, metrics in df.items():\n",
    "    print(f\"Features: {combo}, Accuracy: {metrics['accuracy']:.2f}, F1-score: {metrics['f1_score']:.2f}\")'''"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "pytorch",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
